

/**
* @file msg.h
* @brief 进程间通信
* @author zshare
* @version v1.0
* @date 2022-03-11
* @history  
*/


#ifndef __MSG__H__
#define __MSG__H__



#define CHANNEL_MAX	256	//通道最大数量
#define CHANNEL_NAME "chan"

#define MSG_PRIORITY_GENERAL 0	//普通消息
#define MSG_PRIORITY_URGENCY 1	//紧急消息

typedef struct {
	u8 dst;//目的地址
	u8 src;//源地址
	u8 priority;//优先级
	u8 type;//消息类别
}head_st;

typedef struct {
	u32 len;//消息体长度
	u8 *data;//消息内容
}body_st;

//消息元素
typedef struct MSG_ITEM_ST{
	struct list_head node;//链表节点
	void *msghandle;//消息句柄
	head_st header;//消息头部
	body_st body;//消息体
}msg_item_st;

//通道节点
typedef struct {
	dev_t devno;	//设备号
	u32 minor;		//次设备号
	spinlock_t lock;	//自旋锁保护链表
	wait_queue_head_t wq;
	struct list_head reglist;//普通消息
	struct list_head urglist;//紧急消息
}chan_item_st;

//通道
typedef struct {
	struct cdev cdev;	//字符设备
	dev_t devno;		//设备号
	struct class *dev_class;	//设备类
	u32	chan_count;	//通道数量
	chan_item_st *chan_item;	//通道结构
}ctx_st;


#define get_ctx(ctx)	(p##context)

/** @brief alloc_msg_item
 *			申请消息节点
 * @param	inode[in]	- inode节点
 * @param	pfile[in]	- 文件指针
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static u32 alloc_msg_item(msg_item_st **pmsg_item){
	msg_item_st *msg_item = nil;

	//申请一个消息节点
	pcalloc(msg_item, sizeof(msg_item_st), msg_item_st);
	//初始化链表节点
	INIT_LIST_HEAD(&msg_item->node);

	msg_item->msghandle = (void *)msg_item;
	(*pmsg_item) = msg_item;
	return 0;
}


/** @brief _copy_msg_to_user
 *			拷贝消息到用户空间
 * @param	pitem[in]		- 通道句柄
 * @param	plist[in]		- 消息链表
 * @param	user[in|out]	- 用户空间地址
 * @param	pcount[in|out]	- 拷贝多少条
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static u32 _copy_msg_to_user(chan_item_st *pitem , struct list_head *plist, u8 **user, size_t *pcount){
	msg_item_st *pmsg = nil;
	unsigned long flags = 0;
	u32 count = (*pcount);
	u8 *pos = (*user);

	if(list_empty(plist)){ return 0; }
	list_for_each_entry(pmsg, plist, node){
		//取出该节点
		spin_lock_irqsave(&pitem->lock, flags);
		list_del(&pmsg->node);
		spin_unlock_irqrestore(&pitem->lock, flags);
		wake_up_interruptible(&pitem->wq);
		copy_to_user(pos, &pmsg->header, sizeof(head_st));
		pos += sizeof(head_st);
		copy_to_user(pos, &pmsg->body.len, sizeof(u32));
		pos += sizeof(u32);
		copy_to_user(pos, pmsg->body.data, pmsg->body.len);
		pos += pmsg->body.len;
		if(--count < 1){ return 0; }
	}
	(*user) = pos;
	(*pcount) = count;
	return 0;
}

/** @brief copy_msg_from_user
 *			拷贝消息到内核空间
 * @param	pitem[in]		- 通道句柄
 * @param	user[in]		- 用户空间数据
 * @param	pcount[in|out]	- 拷贝多少条
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static u32 copy_msg_from_user(chan_item_st *pitem , const char __user *user, size_t *pcount)
{
	msg_item_st *pmsg = nil;
	unsigned long flags = 0;
	u32 count = (*pcount), i = 0;
	const u8 *pos = user;
	
	for_zero_travel(i, count){
		alloc_msg_item(&pmsg);
		copy_from_user(&pmsg->header, pos, sizeof(head_st));
		pos += sizeof(head_st);
		copy_from_user(&pmsg->body.len, pos, sizeof(u32));
		pos += sizeof(u32);
		if(pmsg->body.len > 0){
			pcalloc(pmsg->body.data, pmsg->body.len, u8);
			copy_from_user(pmsg->body.data, pos, pmsg->body.len);
			pos += pmsg->body.len;
		}
		//根据优先级和目的地址写入对应的链表
		spin_lock_irqsave(&pitem->lock, flags);
		switch(pmsg->header.priority){
			case MSG_PRIORITY_GENERAL:
				list_add(&pmsg->node, &pitem->reglist);
				break;
			case MSG_PRIORITY_URGENCY:
				list_add(&pmsg->node, &pitem->urglist);
				break;
		}
		spin_unlock_irqrestore(&pitem->lock, flags);
		wake_up_interruptible(&pitem->wq);
	}

	(*pcount) = count;
	return 0;
}


#define copy_msg_to_user(pitem, type, user, count) _copy_msg_to_user(pitem, &pitem->type##list, user, count);




#endif








